package de.fhluebeck.oop.gps.gui;

import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JOptionPane;

import org.jdesktop.swingx.mapviewer.Waypoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.fhluebeck.oop.gps.common.Constants;
import de.fhluebeck.oop.gps.common.DependencyManager;
import de.fhluebeck.oop.gps.common.PoiEnabledWaypoint;
import de.fhluebeck.oop.gps.entity.Category;
import de.fhluebeck.oop.gps.entity.Poi;
import de.fhluebeck.oop.gps.map.MapManager;
import de.fhluebeck.oop.gps.map.WaypointCreateListener;
import de.fhluebeck.oop.gps.map.WaypointUpdateListener;
import de.fhluebeck.oop.gps.service.ICategoryService;
import de.fhluebeck.oop.gps.service.IPoiService;

/**
 * Controller für den GPSView.
 * 
 * Dieser Controller enthält eine Referenz zum MapManager der die Funktionalitäten der Map abdeckt.
 * Die Applikationslogik für Speicher und Aktualisierungsvorgänge sind hier abgebildet
 * 
 * @author ogb, Leif Hitzschke
 * @version 1.00, 05.11.2009
 * 
 */
public class GpsController implements ActionListener, WaypointUpdateListener,
		WaypointCreateListener, FrameCloseListener {

	private final static Logger log = LoggerFactory
			.getLogger(GpsController.class);

	private GpsView view;
	private ICategoryService categoryService = ((ICategoryService) DependencyManager
			.locate(Constants.CATEGORY_SERVICE_DEP_NAME));

	private IPoiService poiService = ((IPoiService) DependencyManager
			.locate(Constants.POI_SERVICE_DEP_NAME));

	private Mode mode;
	private MapManager mapManager;

	private Waypoint activeWaypoint;

	public GpsController(GpsView gpsview) {
		view = gpsview;
		mode = Mode.None;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		log.debug("actionPerformed: {}", e.getActionCommand());

		if (e.getActionCommand() == "cmdClose") {
			System.exit(0);
		} else if (e.getActionCommand() == "cmdSave") {

			handleSave();

		} else if (e.getActionCommand() == "cmdCancel") {

			if (Mode.New.equals(mode)) {
				mapManager.removeWaypoint(activeWaypoint);
			}

			mode = Mode.None;
			clearInputFields();
			setSaveButtonLabel();
		} else if (e.getActionCommand() == "cmdKategorie") {
			KategorieView newView = new KategorieView(view,this);
			newView.setVisible(true);
		} else if (e.getActionCommand() == "cmdAbout") {
			log.debug("OK");
			AboutView newView = new AboutView(view);
			newView.setVisible(true);
		}

	}

	void initializeFields() {
		List<Category> categories = categoryService.readAll();
		view.kategorie.setModel(new DefaultComboBoxModel(categories.toArray()));
		List<Poi> pois = poiService.readAll();

		mapManager = view.mapManager;
		
		for (Poi poi : pois) {
			mapManager.addPoi(poi);
		}
		mapManager.refreshPointsAndRepaint();
		setSaveButtonLabel();
	}

	private void setSaveButtonLabel() {
		view.cmdSave.setText(mode.getText());
	}

	private void clearInputFields() {
		view.LAT.setText("");
		view.LNG.setText("");
		view.description.setText("");
		view.descriptionPOI.setText("");
		view.umkreis.setText("");
		view.description.setEditable(false);
		view.descriptionPOI.setEditable(false);
	}

	@Override
	public void prepareEdit(Waypoint wp) {
		
		createThread();
		
		if (allowManipulate()) {
			if (wp instanceof PoiEnabledWaypoint) {
				mode = Mode.Edit;
				Poi poi = ((PoiEnabledWaypoint) wp).getPoi();
				view.kategorie.setSelectedItem(poi.getCategory());
				view.LAT.setText(String.valueOf(poi.getLat()));
				view.LNG.setText(String.valueOf(poi.getLng()));
				view.description.setText(poi.getName());
				view.descriptionPOI.setText(poi.getDescription());
				view.descriptionPOI.scrollRectToVisible(new Rectangle(0, 0, 10,
						10));
				view.description.setEditable(true);
				view.descriptionPOI.setEditable(true);
				activeWaypoint = wp;
				setSaveButtonLabel();
			}
		}
	}

	/**
	 * 
	 */
	private void createThread() {
		// Neues thread erzeugen
		ThreadUmkreissuche oweThread = new ThreadUmkreissuche("Berechnung", view.umkreis);
		
		// Starten des Threads
		oweThread.start();
	}

	@Override
	public void prepareCreate(Waypoint wp) {
		
		createThread();
		
		mode = Mode.New;
		activeWaypoint = wp;
		clearInputFields();
		view.description.setEditable(true);
		view.descriptionPOI.setEditable(true);
		view.LAT.setText(String.valueOf(wp.getPosition().getLatitude()));
		view.LNG.setText(String.valueOf(wp.getPosition().getLongitude()));		
		setSaveButtonLabel();
	}

	@Override
	public boolean allowManipulate() {
		
		return ! Mode.New.equals(mode) ;
	}
	
	private boolean validate() {
		
		if(view.descriptionPOI.getText().isEmpty() //
				|| view.description.getText().isEmpty() //
				|| view.LAT.getText().isEmpty() //
				|| view.LNG.getText().isEmpty() //
				|| view.kategorie.getSelectedIndex() == -1//
		) {
			return false;
		}
		return true;
	}

	@Override
	public void handleSave() {
		
		if(!validate()) {
			JOptionPane.showMessageDialog(view, "Bitte füllen Sie alle Felder!");
			return ;
		}
		
		switch (mode) {

		case Edit: {
			Poi poi = ((PoiEnabledWaypoint) activeWaypoint).getPoi();
			poi.setCategory((Category) view.kategorie.getSelectedItem());
			poi.setDescription(view.descriptionPOI.getText());
			poi.setName(view.description.getText());

			poi = poiService.update(poi);
			((PoiEnabledWaypoint) activeWaypoint).setPoi(poi);
		}
			break;

		case New: {
			Poi poi = new Poi();
			poi.setCategory((Category) view.kategorie.getSelectedItem());
			poi.setDescription(view.descriptionPOI.getText());
			poi.setName(view.description.getText());
			poi.setLat(Double.valueOf(view.LAT.getText()));
			poi.setLng(Double.valueOf(view.LNG.getText()));
			poi = poiService.create(poi);

			mapManager.removeWaypoint(activeWaypoint);
			mapManager.addPoi(poi);
			mapManager.refreshPointsAndRepaint();

		}
			break;
		default:
		}

		mode = Mode.None;
		activeWaypoint = null;
		clearInputFields();
		setSaveButtonLabel();
	}

	@Override
	public void updateUI() {
		initializeFields();
	}
}
